package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/smartwalle/alipay/v3"
	"github.com/smartwalle/xid"
	"log"
	"net/http"
)

var aliClient *alipay.Client

const (
	kAppId        = "2016092600599040"
	kPrivateKey   = "MIIEowIBAAKCAQEAsPnxwOj/BAiIKjju4WpvWFD+OhqzFoigydrlDrkiY1WWsdt0nw/X9Xu/MyWE1GPJHn/robnEsPDNyaLhIaV4COuyTcqXBTqIuxtfntg79FVNcCT2RRcYdPbBLvBBalJeyjf0DuorgZ5USX3dc4s08JszzBTyHhN/yw9gne57NNXHYk7BoDcs0jLZBQDwaF09pqm2FBgM2i10nH659HK65nkxSxfh5xUMfwoXMz28/PzzvUWK/+nEtVsOxWqJnT9n6f3eDY9pYvmGGrJZjP+ohkT/6TwtbWtslZCxfoYezoj1CwvpF6wWLzgKHaAIO34Qm5eg7h43LSdbDZqt5wRZGQIDAQABAoIBABGNeLDNax2XSwoFA4xP5iM4RT62DzUY7/mVQEqpigOYJY4WWga8p4qtb1U/T2FRVE02GsS7jAqQl5h8EyAnLTSVS+XzRe860vzbxiwW/jtJipio0dQgakiPgLGLGrHU4Znk2svv5cjBT1LKrQAcum9ytTx0h178SBx3tfl0AbxHnVL6u9+KEGMtKFb6WdLlsmd6gvaEPz1cIQsdl0+njGq359yanSVNLYnuDw8fm4l9+j0IdVdFRJOw7+2/gd2z0xazyoYnMZmiQn/+h683avWAu109xiqjBs12NxFmB4hSL9SwFbcMR/uVuVAXnYNw7gtiYFUQVjNeSodf8De0tgECgYEA57f5tjxsov1Gthboywtu+EWUTgdXyYEB95Pf7D3i4M0r47Xb/i4LKCKgTwqSR8aWG2OKfucg06qhsVmNzbD7C/DRi69/gWqKJhDM5apdcRIJPQtKUTzmqX/rqkvyBK0dowSB4QFxIeGPz4ZZV64uY90LRiGHu8PZZ2N9SjfwF3ECgYEAw4V3Rojk2ael5LJwVf5E3awxgnnMe15kvN3S2my4ps8/BeID5PyH9+5PRsXyFn0TrOirW4HCpWK6e5AeSQectQpjkcdjQPJ0QOowxMqQzTyicS8wlXBGUfPkLh/yHalOpHZlEq0S0fcZ77BJxvWpunAT2VMZbO3uuU9GheI+GCkCgYAgmyzSTfJjhQxcNyEO4U7+NJxH1pSt0C98rRxHW/X++CAC7OZGACilvymbtbsbyn/43qrwbImb/1i9YgKoPQ02gu6Zn1pr1ZgW/yo17yEy9fzC0EHm6JD0rQF2dzVZHxsag1nbVZ6by+e2pgsQYXw5pTMe7TzyWP7Qo5lPxktMoQKBgH8JuyQTUk6xhTKBVkgpe+lkNo8GQHxwKpgksRnGxntr8RELd2hTRK0tJElh2BgQkLYqPxynxSbcbTpXu7XLwmBHLcbMfIr4fdynzaQv0cHogct00+ZlGuuowjvN+eyX00c8vhNSbQYLvchlDKq/d9ZxeBQe0EhcmF3DSpk3FQ1xAoGBALlTRPwWSVcZvvcQn/UpkPD7qqxqHAYUDT3tVkaTqUvCk1WI26+R/4ETr+qzLaG41frPhXFhMbpXyo0JkrO2YrP9qS7mKo/5eEaFmp4lq6S+1EGozQc0z7ppmYfh6K1rWYkGUgoXKiYys6uF1ndu9eZRM0gwTTCe8T1p+Q4ri0EF"
	kServerPort   = "9989"
	kServerDomain = "http://127.0.0.1" + ":" + kServerPort
)

func main() {
	var err error

	if aliClient, err = alipay.New(kAppId, kPrivateKey, false); err != nil {
		log.Println("初始化支付宝失败", err)
		return
	}

	// 使用支付宝证书
	if err = aliClient.LoadAppPublicCertFromFile("appCertPublicKey_2016092600599040.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}

	if err = aliClient.LoadAliPayRootCertFromFile("alipayRootCert.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}
	if err = aliClient.LoadAliPayPublicCertFromFile("alipayCertPublicKey_RSA2.crt"); err != nil {
		log.Println("加载证书发生错误", err)
		return
	}

	var s = gin.Default()
	s.GET("/alipay", pay)
	s.GET("/callback", callback)
	s.POST("/notify", notify)
	s.Run(":" + kServerPort)
}

func pay(c *gin.Context) {
	// 自己根据前端数据拼接
	var tradeNo = fmt.Sprintf("%d", xid.Next())

	var p = alipay.TradePagePay{}
	p.NotifyURL = kServerDomain + "/notify"
	p.ReturnURL = kServerDomain + "/callback"
	p.Subject = "链力售后:" + tradeNo
	p.OutTradeNo = tradeNo
	p.TotalAmount = "0.01"
	p.ProductCode = "FAST_INSTANT_TRADE_PAY"

	url, _ := aliClient.TradePagePay(p)

	c.Redirect(http.StatusTemporaryRedirect, url.String())
}

func callback(c *gin.Context) {
	c.Request.ParseForm()
	var outTradeNo = c.Request.Form.Get("out_trade_no")
	var p = alipay.TradeQuery{}
	p.OutTradeNo = outTradeNo
	rsp, err := aliClient.TradeQuery(p)
	if err != nil {
		c.String(http.StatusBadRequest, "验证订单 %s 信息发生错误: %s", outTradeNo, err.Error())
		return
	}
	if rsp.IsSuccess() == false {
		c.String(http.StatusBadRequest, "验证订单 %s 信息发生错误: %s-%s", outTradeNo, rsp.Content.Msg, rsp.Content.SubMsg)
		return
	}

	c.String(http.StatusOK, "订单 %s 支付成功", outTradeNo)
}

func notify(c *gin.Context) {
	c.Request.ParseForm()

	ok, err := aliClient.VerifySign(c.Request.Form)
	if err != nil {
		log.Println("异步通知验证签名发生错误", err)
		return
	}

	if ok == false {
		log.Println("异步通知验证签名未通过")
		return
	}

	log.Println("异步通知验证签名通过")

	var outTradeNo = c.Request.Form.Get("out_trade_no")
	var p = alipay.TradeQuery{}
	p.OutTradeNo = outTradeNo
	rsp, err := aliClient.TradeQuery(p)
	if err != nil {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s \n", outTradeNo, err.Error())
		return
	}
	if rsp.IsSuccess() == false {
		log.Printf("异步通知验证订单 %s 信息发生错误: %s-%s \n", outTradeNo, rsp.Content.Msg, rsp.Content.SubMsg)
		return
	}

	log.Printf("订单 %s 支付成功 \n", outTradeNo)
}
